﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using MonoGame;

namespace TunnelsOfDeath.Objects
{
    class Enemy : Sprite
    {

        protected Vector2[] positionList = new Vector2[4];
        protected bool searchRight = true;
        protected short counter = 2;
        protected short currentCounter = 1;

        public Enemy(
            int _textureID,
            Dictionary<Direction, Vector2> _animationTable,
            Dictionary<Direction,int> _animationFrames,
            ObjectType _type,
            Vector2 _position,
            double _delay,
            bool _searchRight,
            short _counter)
            : base(_textureID, _animationTable, _animationFrames, _type, _position, _delay)
        {
            positionList = FillPositions();
            searchRight = _searchRight;
            ObjectDirection = Direction.right;
            counter = _counter;
            currentCounter = _counter;
        }

        protected bool DetectPlayer()
        {

            bool value = false;
            foreach (Vector2 item in positionList)
            {
                Vector2 pos = position + item;
                if (Globals.Map[(int)pos.X, (int)pos.Y] != null && Globals.Map[(int)pos.X, (int)pos.Y].Type == ObjectType.player)
                {
                    Globals.ObjectManager.GenerateExplosion(position, GetTag());
                    value = true;
                    break;
                }
            }
            return value;
        }

        public override void UpdatePosition(double _tag)
        {
            if (!CheckTag(_tag))
            {

                if (DetectPlayer())
                    return;

                if (currentCounter != 0)
                {
                    currentCounter--;
                }
                else
                {

                    currentCounter = counter;

                    Vector2 nextPosition;
                    Vector2 wall;

                    if (ObjectDirection != Direction.stopped)
                    {
                        int directionNumber = DirectionToNumber(ObjectDirection);

                        nextPosition = position + positionList[directionNumber];
                        wall = position + positionList[ShiftDirection(directionNumber)];



                        if (Globals.Map[(int)nextPosition.X, (int)nextPosition.Y] == null && Globals.Map[(int)wall.X, (int)wall.Y] != null)
                        {

                            MoveTo(nextPosition);

                        }
                        else if (Globals.Map[(int)wall.X, (int)wall.Y] == null)
                        {
                            ObjectDirection = NumberToDirection(ShiftDirection(directionNumber));
                            MoveTo(wall);

                        } else
                        {
                            int free = GetPossiblePosition();
                            if (free != -1)
                            {
                                ObjectDirection = NumberToDirection(free);
                                nextPosition = position + positionList[free];
                                MoveTo(nextPosition);
                            }
                        }

                    }

                    
                }
            }
        }


        protected int ShiftDirection (int _direction)
        {
            int direction = 0;

            if (searchRight)
            {
                direction = 1;
            }
            else
            {
                direction = -1;
            }

            _direction += direction;

            if (_direction > 3)
            {
                _direction = 1;
            }
            else if (_direction < 0)
            {
                _direction = 3;
            }

            return _direction;
        }

        protected int GetOpposite(int _position)
        {
            switch (_position)
            {
                case 0:
                    return 2;
                case 1:
                    return 3;
                case 2:
                    return 0;
                case 3:
                    return 1;
                default:
                    return 0;
            }
        }

        protected int GetPossiblePosition()
        {
            byte checkedDirections = 0;
            int toReturn = -1;
            int current = DirectionToNumber(ObjectDirection);
            short direction = 0;
            bool backPossible = false;
            int backDirection = GetOpposite(current);


            if (searchRight)
            {
                direction = 1;
            }
            else
            {
                direction = -1;
            }


            do
            {

                current += direction;
                if (current > 3)
                {
                    current = 1;
                }
                else if (current < 0)
                {
                    current = 3;
                }


                checkedDirections++;
                Vector2 toCheck = positionList[current];
                toCheck = position + toCheck;

                if (Globals.Map[(int)toCheck.X, (int)toCheck.Y] == null)
                {
                    if (current == backDirection)
                    {
                        backPossible = true;
                    }
                    else
                    {
                        return current;
                    }
                }


            } while (checkedDirections < 3);

            if (backPossible)
            {
                toReturn = backDirection;
                return toReturn;
            }

            if (checkedDirections >= 3)
            {
                toReturn = -1;
            }

            return toReturn;
        }

        protected Vector2[] FillPositions()
        {
            int indexer = 0;
            Vector2[] allDirections = new Vector2[8];
            Vector2[] toReturn = new Vector2[4];

            foreach (Vector2 item in GetAllFieldsAround())
            {
                allDirections[indexer] = item;
                indexer++;
            }

            toReturn[0] = allDirections[1];
            toReturn[1] = allDirections[4];
            toReturn[2] = allDirections[6];
            toReturn[3] = allDirections[3];

            return toReturn;
        }

        protected int DirectionToNumber(Direction _direction)
        {
            switch (_direction)
            {
                case Direction.up:
                    return 0;
                case Direction.down:
                    return 2;
                case Direction.left:
                    return 3;
                case Direction.right:
                    return 1;
                default:
                    return -1;
            }
        }

        protected Direction NumberToDirection(int _value)
        {
            switch (_value)
            {
                case 0:
                    return Direction.up;
                case 2:
                    return Direction.down;
                case 3:
                    return Direction.left;
                case 1:
                    return Direction.right;
                default:
                    return Direction.stopped;
            }
        }

    }
}
